import { getDependencyVersionFromPackageJson, type Tree } from '@nx/devkit';
import { clean, coerce, major } from 'semver';
import {
  backwardCompatibleVersions,
  type PackageCompatVersions,
  type PackageLatestVersions,
} from '../../utils/backward-compatible-versions';
import * as latestVersions from '../../utils/versions';
import { angularVersion } from '../../utils/versions';

export function getInstalledAngularDevkitVersion(tree: Tree): string | null {
  return (
    getDependencyVersionFromPackageJson(
      tree,
      '@angular-devkit/build-angular'
    ) ?? getDependencyVersionFromPackageJson(tree, '@angular/build')
  );
}

export function getInstalledAngularVersion(tree: Tree): string {
  const installedAngularVersion = getDependencyVersionFromPackageJson(
    tree,
    '@angular/core'
  );

  if (
    !installedAngularVersion ||
    installedAngularVersion === 'latest' ||
    installedAngularVersion === 'next'
  ) {
    return clean(angularVersion) ?? coerce(angularVersion).version;
  }

  return (
    clean(installedAngularVersion) ?? coerce(installedAngularVersion).version
  );
}

export function getInstalledAngularMajorVersion(tree: Tree): number {
  return major(getInstalledAngularVersion(tree));
}

export function getInstalledAngularVersionInfo(tree: Tree) {
  const installedVersion = getInstalledAngularVersion(tree);

  return {
    version: installedVersion,
    major: major(installedVersion),
  };
}

export function getInstalledPackageVersionInfo(tree: Tree, pkgName: string) {
  const version = getDependencyVersionFromPackageJson(tree, pkgName);

  return version ? { major: major(coerce(version)), version } : null;
}

export function versions(
  tree: Tree
): PackageLatestVersions | PackageCompatVersions {
  const majorAngularVersion = getInstalledAngularMajorVersion(tree);
  switch (majorAngularVersion) {
    case 18:
      return backwardCompatibleVersions.angularV18;
    case 19:
      return backwardCompatibleVersions.angularV19;
    default:
      return latestVersions;
  }
}

/**
 * Temporary helper to abstract away the version of angular-rspack to be installed
 * until we stop supporting Angular 19.
 */
export function getAngularRspackVersion(tree: Tree): string | null {
  const majorAngularVersion = getInstalledAngularMajorVersion(tree);

  if (majorAngularVersion === 19) {
    return backwardCompatibleVersions.angularV19.angularRspackVersion;
  }
  if (majorAngularVersion >= 20) {
    // Starting with Angular 20, we can use an Angular Rspack version that is
    // aligned with the Nx version
    return latestVersions.nxVersion;
  }

  // Lower versions of Angular are not supported
  return null;
}
